package palms.locationserver;

import java.io.IOException;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;

import palms.exceptions.InvalidClassMessage;
import palms.exceptions.InvalidTicketMessage;
import palms.exceptions.InvalidUserMessage;
import palms.location.results.ALocation;
import palms.locationsearch.GooglePlacesSearch;
import palms.messages.SLRequest;
import palms.messages.SLResponse;
import palms.messages.SLServiceInfo;
import palms.messages.SLServiceResults;
import palms.messages.TicketSL;
import palms.security.PalmsSecurityManager;

public class LocationWorker implements Runnable {

	private Socket s;
	private LocationLogic ll;
	
	public LocationWorker(Socket s, LocationLogic ll){
		this.s = s;
		this.ll = ll;
	}
	
	@Override
	public void run() {
		try {
			
			SLRequest sr = SLRequest.receiveTroughSocket(s);
			processSLRequest(sr);
				
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidClassMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidUserMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidTicketMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	public void processSLRequest(SLRequest slreq) throws InvalidKeyException, NoSuchAlgorithmException, IOException, ClassNotFoundException, IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException{
		
		System.out.println("-->Processing a Request");
		
		SealedObject sealed_slticket = slreq.getSlticket();
		SealedObject sealed_serviceinfo = slreq.getServiceinfo();
		
		TicketSL slticket = (TicketSL) PalmsSecurityManager.DesealObjectWithK(sealed_slticket, ll.getKeySl());
		SLServiceInfo serviceinfo = (SLServiceInfo) PalmsSecurityManager.DesealObjectWithK(sealed_serviceinfo, slticket.getSessionKey());
		
		System.out.println();
		System.out.println("-->Processing SL Ticket.");
		System.out.println("-->The ticket expiring date: " + slticket.getValidity());
		System.out.println("-->Client/SL session key: " + PalmsSecurityManager.asHex(slticket.getSessionKey().getEncoded()));
		System.out.println("-->SI ip: " + slticket.getIp());

		
		System.out.println();
		System.out.println("-->Processing Service Info.");
		System.out.println("-->Latitude: " + serviceinfo.getLat());
		System.out.println("-->Longitude: " + serviceinfo.getLog());
		System.out.println("-->Time of request: " + serviceinfo.getTimestamp());
		System.out.println("-->Type of request: " + serviceinfo.getType());
		System.out.println();
		
		if(verifySLTicket(slticket, serviceinfo)){
			
			System.out.println("-->Querying for locations");
			
			GooglePlacesSearch gps = new GooglePlacesSearch();
			gps.setLocation(serviceinfo.getLat(), serviceinfo.getLog());
			gps.setTypes(serviceinfo.getType()); 
			LinkedList<ALocation> reslist = gps.getResults();

			for(ALocation l : reslist){
				System.out.println("-->Found a place named "+l.getName());
			}
			
			System.out.println("-->Found a total of "+reslist.size()+" results.");
			
			SLServiceResults slsres = new SLServiceResults();
			slsres.setResult(reslist);
			SealedObject sealed_slsres = PalmsSecurityManager.SealObjectWithK(slsres, slticket.getSessionKey());
			
			SLResponse slresponse = new SLResponse(sealed_slsres);
			
			System.out.println("-->Sealed SL Service Response:" + sealed_slsres);
			System.out.println("-->Sending response");
			slresponse.sendTroughSocket(s);
			
		}else{
			PalmsSecurityManager.sendError(s, new InvalidTicketMessage());
		}
		
		
	}
	
	public boolean verifySLTicket(TicketSL ticket, SLServiceInfo info){
			
		if(ticket.getIp().equals(s.getInetAddress().getHostAddress()) &&
		   ticket.getValidity() > info.getTimestamp()){
			return true;
		}
		else
			return false;
	}
	
}
